﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml.Linq;

namespace StatisticsAggregator
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private List<bool> _isDirty = null;

        private void MainForm_Load(object sender, EventArgs e)
        {
            _isDirty = new List<bool>();
            for (int i = 0; i < tabControl.TabCount; i++)
                _isDirty.Add(true);

            SetStatisticsIsDirty(false);
        }

        private void SetStatisticsIsDirty(bool forceReload = false)
        {
            for (int i = 0; i < _isDirty.Count; i++)
            {
                _isDirty[i] = true;
            }

            if (forceReload)
                UpdateStatistics(tabControl.SelectedIndex);
        }

        private void UpdateStatistics(int tab)
        {
            var userTable = new StatisticsDataSetTableAdapters.UserTableAdapter();
            var reportTable = new StatisticsDataSetTableAdapters.ReportTableAdapter();
            var misprintTable = new StatisticsDataSetTableAdapters.MisprintTableAdapter();
            var lettersTable = new StatisticsDataSetTableAdapters.MisprintLetterTableAdapter();

            // reports

            if (tab == 0 && _isDirty[0])
            {
                this.reportViewTableAdapter.Fill(this.statisticsDataSet.ReportView);

                _isDirty[0] = false;
            }

            // summary

            if (tab == 1 && _isDirty[1])
            {

                var reports = Convert.ToInt32(reportTable.CountReports());
                var users = Convert.ToInt32(userTable.CountUsers());
                var misprints = Convert.ToInt32(misprintTable.CountMisprints());
                var letters = Convert.ToInt32(lettersTable.CountLetters());

                _misprintsTotal = misprints;
                _lettersTotal = letters;

                statisticsDataSet.EnforceConstraints = false;
                this.userReportsViewTableAdapter.Fill(this.statisticsDataSet.UserReportsView);
                this.misprintByTypeViewTableAdapter.Fill(this.statisticsDataSet.MisprintByTypeView);
                this.misprintLetterCountTableAdapter.Fill(this.statisticsDataSet.MisprintLetterCountView);
                this.misprintLetterDistanceTableAdapter.Fill(this.statisticsDataSet.MisprintLetterDistanceView);
                this.countMisprintLetterViewTableAdapter.Fill(this.statisticsDataSet.CountMisprintLetterView);

                try
                {
                    statisticsDataSet.EnforceConstraints = true;
                }
                catch { }

                dataGridStatisticsSummary.Rows.Clear();
                AddRow(dataGridStatisticsSummary, "Всего отчетов", reports.ToString());
                AddRow(dataGridStatisticsSummary, "Всего пользователей", users.ToString());
                AddRow(dataGridStatisticsSummary, "Всего опечаток", misprints.ToString());
                AddRow(dataGridStatisticsSummary, "Среднее количество опечаток на отчет", String.Format("{0:0.00}", ((float)misprints / reports)));

                try
                {
                    chartMisprintLetter.DataBind();
                    chartMisprintType.DataBind();
                }
                catch { }

                _isDirty[1] = false;
            }

            // users

            if (tab == 2 && _isDirty[2])
            {
                UpdateUserStatistics();

                _isDirty[2] = false;
            }
        }

        private int _misprintsTotal;
        private int _lettersTotal;
        private int _userMisprintsTotal;
        private int _userLettersTotal;

        private void UpdateUserStatistics(bool updateSource = true)
        {
            var reportTable = new StatisticsDataSetTableAdapters.ReportTableAdapter();
            var misprintTable = new StatisticsDataSetTableAdapters.MisprintTableAdapter();
            var lettersTable = new StatisticsDataSetTableAdapters.MisprintLetterTableAdapter();
            var userTable = new StatisticsDataSetTableAdapters.UserTableAdapter();
            var userInfoTable = new StatisticsDataSetTableAdapters.UserInfoTableAdapter();

            if (updateSource)
            {
                this.userViewTableAdapter.Fill(this.statisticsDataSet.UserView);
                this.userTableAdapter.Fill(this.statisticsDataSet.User);
            }

            long selectedUserId = 0;
            int userReports = 0, userMisprints = 0, userLetters = 0;

            if (comboBoxUser.Items.Count != 0 &&
                comboBoxUser.SelectedValue != null && long.TryParse(comboBoxUser.SelectedValue.ToString(), out selectedUserId))
            {
                userReports = Convert.ToInt32(reportTable.CountReportsByUserId(selectedUserId));
                userMisprints = Convert.ToInt32(misprintTable.CountMisprintsByUserId(selectedUserId));
                userLetters = Convert.ToInt32(lettersTable.CountLettersByUserId(selectedUserId));

                _userMisprintsTotal = userMisprints;
                _userLettersTotal = userLetters;
            }

            dataGridStatisticsUser.Rows.Clear();
            AddRow(dataGridStatisticsUser, "Отчеты", userReports.ToString());
            AddRow(dataGridStatisticsUser, "Опечатки", userMisprints.ToString());
            AddRow(dataGridStatisticsUser, "Среднее количество опечаток на отчет", String.Format("{0:0.00}", ((float)userMisprints / userReports)));
            AddRow(dataGridStatisticsUser, "Статус", TranslateRole(userTable.GetUserRole(selectedUserId)));

            foreach (var entry in userInfoTable.GetData(selectedUserId))
            {
                AddRow(dataGridStatisticsUser, TranslateUserInfo(entry.Key), entry.Value);
            }

            statisticsDataSet.EnforceConstraints = false;
            this.userMisprintByTypeViewTableAdapter.Fill(this.statisticsDataSet.UserMisprintByTypeView, selectedUserId);
            this.userMisprintsViewTableAdapter.Fill(this.statisticsDataSet.UserMisprintsView, selectedUserId);
            this.userCountMisprintLetterViewTableAdapter.Fill(this.statisticsDataSet.UserCountMisprintLetterView, selectedUserId);
            this.userMisprintByTypeViewTableAdapter.Fill(this.statisticsDataSet.UserMisprintByTypeView, selectedUserId);
            this.userMisprintLetterCountTableAdapter.Fill(this.statisticsDataSet.UserMisprintLetterCountView, selectedUserId);
            this.userMisprintLetterDistanceTableAdapter.Fill(this.statisticsDataSet.UserMisprintLetterDistanceView, selectedUserId);

            try
            {
                statisticsDataSet.EnforceConstraints = true;
            }
            catch { }
            
            try
            {
                chartUserMisprintLetters.DataBind();
                chartUserMisprintType.DataBind();
            }
            catch { }
        }

        private void AddRow(DataGridView dataGrid, string name, string value)
        {
            DataGridViewRow row = new DataGridViewRow();
            row.Cells.Add(new DataGridViewTextBoxCell() { Value = name  });
            row.Cells.Add(new DataGridViewTextBoxCell() { Value = value });
            dataGrid.Rows.Add(row);
        }

        private void btnAddReportFile_Click(object sender, EventArgs e)
        {
            openFileDialog.FileName = "";
            openFileDialog.Filter = "Xml files (*.xml)|*.xml|All files (*.*)|*.*";
            openFileDialog.FilterIndex = 1;

            int totalReports = 0, loadedReports = 0;

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                using (var operation = new LongTermOperation())
                {
                    try
                    {
                        ReportsHelper.LoadFromXml(openFileDialog.OpenFile(), out loadedReports, out totalReports);
                    }
                    catch
                    {
                    }
                }

                if (loadedReports > 0)
                    SetStatisticsIsDirty(true);

                UpdateStatus(String.Format("Загружено отчетов: {1} из {0}", totalReports, loadedReports));
            }
        }

        private void btnAddReportDir_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                int gTotalReports = 0, gLoadedReports = 0;

                using (var operation = new LongTermOperation())
                {
                    DirectoryInfo directoryInfo = new DirectoryInfo(folderBrowserDialog.SelectedPath);
                    FileInfo[] files = directoryInfo.GetFiles("*.xml");
                    foreach (FileInfo fileInfo in files)
                    {
                        try
                        {
                            int totalReports, loadedReports;
                            ReportsHelper.LoadFromXml(fileInfo.OpenRead(), out loadedReports, out totalReports);
                            gTotalReports += totalReports;
                            gLoadedReports += loadedReports;
                        }
                        catch
                        {
                        }
                    }
                }

                if (gLoadedReports > 0)
                    SetStatisticsIsDirty(true);

                UpdateStatus(String.Format("Загружено отчетов: {1} из {0}", gTotalReports, gLoadedReports));
            }
        }

        private void btnSelectAllReports_Click(object sender, EventArgs e)
        {
            using (var operation = new LongTermOperation())
            {
                foreach (DataGridViewRow row in dataGridReports.Rows)
                {
                    DataGridViewCheckBoxCell cell = (row.Cells[0] as DataGridViewCheckBoxCell);
                    cell.Value = cell.TrueValue;
                }
            }
        }

        private void btnClearSelectReports_Click(object sender, EventArgs e)
        {
            using (var operation = new LongTermOperation())
            {
                foreach (DataGridViewRow row in dataGridReports.Rows)
                {
                    DataGridViewCheckBoxCell cell = (row.Cells[0] as DataGridViewCheckBoxCell);
                    cell.Value = cell.FalseValue;
                }
            }
        }

        private void btnDeleteReports_Click(object sender, EventArgs e)
        {
            int deletedReports = 0;

            using (var operation = new LongTermOperation())
            {
                foreach (DataGridViewRow row in dataGridReports.Rows)
                {
                    DataGridViewCheckBoxCell cell = (row.Cells[0] as DataGridViewCheckBoxCell);

                    if (cell.Value == cell.TrueValue)
                    {
                        deletedReports += ReportsHelper.DeleteReport(long.Parse(row.Cells[1].Value.ToString()));
                    }
                }
            }

            if (deletedReports > 0)
                SetStatisticsIsDirty(true);

            UpdateStatus(String.Format("Удалено отчетов: {0}", deletedReports));
        }

        private void dataGridStatisticsSummary_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 0)
            {
                dataGridStatisticsSummary.Rows[e.RowIndex].Selected = false;
            }
        }

        private void comboBoxUser_SelectedIndexChanged(object sender, EventArgs e)
        {
        }

        private void dataGridStatisticsUser_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 0)
            {
                dataGridStatisticsUser.Rows[e.RowIndex].Selected = false;
            }
        }

        private void UpdateStatus(string text)
        {
            toolStripStatus.Text = text;
        }

        private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
        {
            UpdateStatus("");

            UpdateStatistics(tabControl.SelectedIndex);
        }

        private void btnShowUserStats_Click(object sender, EventArgs e)
        {
            UpdateUserStatistics(false);
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            using (var operation = new LongTermOperation())
            {
                UpdateStatistics(0);
            }
        }

        private string TranslateUserInfo(string code)
        {
            string value = code;
            switch (value)
            {
                case "Job":
                    value = "Место работы";
                    break;
                case "Seniority":
                    value = "Стаж работы";
                    break;
                case "Faculty":
                    value = "Факультет";
                    break;
                case "Specialty":
                    value = "Специальность";
                    break;
                case "Course":
                    value = "Курс";
                    break;
            }

            return value;
        }

        private string TranslateRole(string code)
        {
            string value = code;
            switch (value)
            {
                case "student":
                    value = "Студент";
                    break;
                case "worker":
                    value = "Работает";
                    break;
            }

            return value;
        }

        private string TranslateMisprintType(string code)
        {
            string value = code;
            switch (value)
            {
                case "extra-letter":
                    value = "Лишний символ";
                    break;
                case "missed-letter":
                    value = "Пропущенный символ";
                    break;
                case "replace-letter":
                    value = "Замененный символ";
                    break;
                case "incorrect-order":
                    value = "Неправильный порядок символов";
                    break;
                case "case-invariant":
                    value = "Неправильный регистр символов";
                    break;
            }

            return value;
        }

        private void dataGridReports_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 5)
            {
                e.Value = TranslateRole(e.Value.ToString());
            }
        }

        private void dataGridMisprintByType_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            dataGridMisprintByType.Rows[e.RowIndex].Selected = false;

            if (e.ColumnIndex == 0)
            {
                e.Value = TranslateMisprintType(e.Value.ToString());
            }
            else if (e.ColumnIndex == 2)
            {
                e.Value = String.Format("{0:0.00}", 
                    100.0f * Int32.Parse(dataGridMisprintByType.Rows[e.RowIndex].Cells[1].Value.ToString()) / _misprintsTotal);
            }
        }

        private void dataGridUserMisprintByType_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            dataGridUserMisprintByType.Rows[e.RowIndex].Selected = false;

            if (e.ColumnIndex == 0)
            {
                e.Value = TranslateMisprintType(e.Value.ToString());
            }
            else if (e.ColumnIndex == 2)
            {
                e.Value = String.Format("{0:0.00}", 
                    100.0f * Int32.Parse(dataGridUserMisprintByType.Rows[e.RowIndex].Cells[1].Value.ToString()) / _userMisprintsTotal);
            }
        }

        private void dataGridCountMisprintLetter_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            dataGridCountMisprintLetter.Rows[e.RowIndex].Selected = false;
            
            if (e.ColumnIndex == 2)
            {
                e.Value = String.Format("{0:0.00}", 
                    100.0f * Int32.Parse(dataGridCountMisprintLetter.Rows[e.RowIndex].Cells[1].Value.ToString()) / _lettersTotal);
            }
        }

        private void dataGridUserCountMisprintLetter_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            dataGridUserCountMisprintLetter.Rows[e.RowIndex].Selected = false;

            if (e.ColumnIndex == 2)
            {
                e.Value = String.Format("{0:0.00}",
                    100.0f * Int32.Parse(dataGridUserCountMisprintLetter.Rows[e.RowIndex].Cells[1].Value.ToString()) / _userLettersTotal);
            }
        }

        private void chartMisprintsType_CustomizeLegend(object sender, System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs e)
        {
            for (int i = 0; i < e.LegendItems.Count; i++)
                e.LegendItems[i].Cells[1].Text = TranslateMisprintType(e.LegendItems[i].Cells[1].Text);
        }

        private void chartUserMisprintType_CustomizeLegend(object sender, System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs e)
        {
            for (int i = 0; i < e.LegendItems.Count; i++)
                e.LegendItems[i].Cells[1].Text = TranslateMisprintType(e.LegendItems[i].Cells[1].Text);
        }

        private void chartMisprintsType_FormatNumber(object sender, System.Windows.Forms.DataVisualization.Charting.FormatNumberEventArgs e)
        {
            if (e.ElementType == System.Windows.Forms.DataVisualization.Charting.ChartElementType.DataPoint)
            {
                e.LocalizedValue = String.Format("{0:0.0}%", 100.0f * float.Parse(e.Value.ToString()) / _misprintsTotal);
            }
        }

        private void chartUsersReportsCount_FormatNumber(object sender, System.Windows.Forms.DataVisualization.Charting.FormatNumberEventArgs e)
        {
            if (e.ElementType == System.Windows.Forms.DataVisualization.Charting.ChartElementType.DataPoint)
            {
                e.LocalizedValue = String.Format("{0:0.0}%", 100.0f * float.Parse(e.Value.ToString()) / _lettersTotal);
            }
        }

        private void chartUserMisprintLetters_FormatNumber(object sender, System.Windows.Forms.DataVisualization.Charting.FormatNumberEventArgs e)
        {
            if (e.ElementType == System.Windows.Forms.DataVisualization.Charting.ChartElementType.DataPoint)
            {
                e.LocalizedValue = String.Format("{0:0.0}%", 100.0f * float.Parse(e.Value.ToString()) / _userLettersTotal);
            }
        }

        private void chartUserMisprintType_FormatNumber(object sender, System.Windows.Forms.DataVisualization.Charting.FormatNumberEventArgs e)
        {
            if (e.ElementType == System.Windows.Forms.DataVisualization.Charting.ChartElementType.DataPoint)
            {
                e.LocalizedValue = String.Format("{0:0.0}%", 100.0f * float.Parse(e.Value.ToString()) / _userMisprintsTotal);
            }
        }

        private void chartMisprintLetter_CustomizeLegend(object sender, System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs e)
        {
            for (int i = 0; i < e.LegendItems.Count; i++)
                e.LegendItems[i].Cells[1].Text = e.LegendItems[i].Cells[1].Text.Length != 1  ? "Пробел" : e.LegendItems[i].Cells[1].Text;
        }

        private void chartUserMisprintLetters_CustomizeLegend(object sender, System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs e)
        {
            for (int i = 0; i < e.LegendItems.Count; i++)
                e.LegendItems[i].Cells[1].Text = e.LegendItems[i].Cells[1].Text.Length != 1 ? "Пробел" : e.LegendItems[i].Cells[1].Text;
        }

        private void dataGridDistance_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 0)
            {
                dataGridDistance.Rows[e.RowIndex].Selected = false;
            }
        }

        private void dataGridLetterCount_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 0)
            {
                dataGridLetterCount.Rows[e.RowIndex].Selected = false;
            }
            else if (e.ColumnIndex == 2)
            {
                e.Value = String.Format("{0:0.00}",
                    100.0f * Int32.Parse(dataGridLetterCount.Rows[e.RowIndex].Cells[1].Value.ToString()) / _misprintsTotal);
            }
        }

        private void dataGridUserDistance_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 0)
            {
                dataGridUserDistance.Rows[e.RowIndex].Selected = false;
            }
        }

        private void dataGridUserLetterCount_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 0)
            {
                dataGridUserLetterCount.Rows[e.RowIndex].Selected = false;
            }
            else if (e.ColumnIndex == 2)
            {
                e.Value = String.Format("{0:0.00}",
                    100.0f * Int32.Parse(dataGridUserLetterCount.Rows[e.RowIndex].Cells[1].Value.ToString()) / _userMisprintsTotal);
            }
        }
    }
}
